﻿namespace NTLib.Core.UTest.Threading
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using Core.Threading;

    [TestClass()]
    public class ReaderWriterLockSlimExtTest
    {

        #region Methods

        [TestCategory("Core.Threading")]
        [TestMethod]
        public void ReaderWriterSlimLock_ReadTest()
        {
            ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

            using (var lockerItem = locker.LockRead())
            {
                Assert.IsTrue(locker.IsReadLockHeld);
            }

            Assert.IsFalse(locker.IsReadLockHeld);
        }


        [TestCategory("Core.Threading")]
        [TestMethod]
        public void ReaderWriterSlimLock_WriteTest()
        {
            ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

            using (var lockerItem = locker.LockWrite())
            {
                Assert.IsTrue(locker.IsWriteLockHeld);
            }

            Assert.IsFalse(locker.IsWriteLockHeld);
        }

        [TestCategory("Core.Threading")]
        [TestMethod]
        public void ReaderWriterSlimLock_ReadTestAsync_withCancel()
        {
            ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
            CancellationTokenSource tokenSource = new CancellationTokenSource();

            using (var lockerItem2 = locker.LockWrite())
            {
                try
                {
                    tokenSource.CancelAfter(1000);
                    TaskCompletionSource<bool> t = new TaskCompletionSource<bool>();
                    ThreadPool.QueueUserWorkItem((e) =>
                       {
                           try
                           {
                               using (var lockerItem = locker.LockRead(tokenSource.Token))
                               {
                                   Assert.Fail("Shouln't reach this code section");
                               }
                           }
                           catch (OperationCanceledException)
                           {

                           }
                           catch (Exception ex)
                           {
                               t.SetException(ex);
                               return;
                           }
                           t.SetResult(true);
                       });
                    t.Task.Wait();

                }
                catch (OperationCanceledException)
                {

                }
                catch
                {
                    Assert.Fail("Shouln't reach this code section");
                }
            }
        }

        #endregion
    }
}
